﻿// Imports
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;

namespace Nickel
{

    /// <summary>
    /// Summary description for StringHelper
    /// </summary>
    public class StringHelper
    {

        /// <summary>
        /// Decrypts a string using TDES algorithm against MD5 salt
        /// </summary>
        /// <param name="encryptedMessage">The string to decrypt</param>
        /// <param name="salt">The unhashed salt used to encrypt the string</param>
        /// <returns>Decrypted string</returns>
        public static string Decrypt(string message)
        {

            // Create a byte array to store encrypted data
            byte[] Results;

            // Create an instance of a UTF-8 encoder
            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            // We hash the salt using MD5
            // We use the MD5 hash generator as the result is a 128 bit byte array
            // which is a valid length for the TripleDES encoder we use below
            MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Settings.PASS_PHRASE));

            // Create a new TripleDESCryptoServiceProvider object
            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            // Setup the decoder
            TDESAlgorithm.Key = TDESKey;
            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            // Convert the input string to a byte array
            byte[] DataToDecrypt = Convert.FromBase64String(message);

            try
            {

                // Attempt to decrypt the string
                ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor();
                Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);

                // Clean up
                Decryptor = null;

            }
            finally
            {

                // Clear the TripleDes and Hashprovider services of any sensitive information
                TDESAlgorithm.Clear();
                HashProvider.Clear();

            }

            // Convert byte array to string
            string decryptedMessage = UTF8.GetString(Results);

            // Clean up
            HashProvider = null;
            Results = null;
            TDESAlgorithm = null;
            UTF8 = null;

            // Return the decrypted string
            return decryptedMessage;

        }

        /// <summary>
        /// Encodes title string as URL friendly yet human readable text
        /// </summary>
        /// <param name="title">Title to encode</param>
        /// <returns>Encoded string</returns>
        public static string Encode(string title)
        {

            // Replace non-alphanumeric characters with hyphens
            title = Regex.Replace(title.Trim().ToLower(), @"[^a-zA-Z0-9\s]", "-");

            // Turn spaces to hyphens
            title = title.Replace(" ", "-");

            // Replace multiple hyphens with one
            Regex twoHyphens = new Regex(@"--");
            while (twoHyphens.IsMatch(title)) title = twoHyphens.Replace(title, "-");
            twoHyphens = null;

            // Remove beginning and trailing hyphens
            if (title.Length > 0) 
                while (title.Substring(0, 1) == "-") 
                    title = title.Substring(1, title.Length - 1);
            if (title.Length > 0) 
                while (title.Substring(title.Length - 1, 1) == "-") 
                    title = title.Substring(0, title.Length - 1);

            // Return title
            return title;

        }

        /// <summary>
        /// Encrypts a string using TDES algorithm with MD5 salt
        /// </summary>
        /// <param name="message">The string to encrypt</param>
        /// <param name="salt">Salt string to hash</param>
        /// <returns>Encrypted string</returns>
        public static string Encrypt(string message)
        {

            // Create a byte array to store encrypted data
            byte[] Results;

            // Create an instance of a UTF-8 encoder
            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            // Hash the salt using MD5
            // We use the MD5 hash generator as the result is a 128 bit byte array
            // which is a valid length for the TripleDES encoder we use below
            MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Settings.PASS_PHRASE));

            // Create a new TripleDESCryptoServiceProvider object
            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            // Setup the encoder
            TDESAlgorithm.Key = TDESKey;
            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            // Convert the input string to a byte[]
            byte[] DataToEncrypt = UTF8.GetBytes(message);

            try
            {

                // Attempt to encrypt the string
                ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();
                Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);

                // Clean up
                Encryptor = null;

            }
            finally
            {

                // Clear the TripleDes and Hashprovider services of any sensitive information
                TDESAlgorithm.Clear();
                HashProvider.Clear();

            }

            // Convert byte array to string
            string encryptedMessage = Convert.ToBase64String(Results);

            // Clean up
            HashProvider = null;
            Results = null;
            TDESAlgorithm = null;
            UTF8 = null;

            // Return the encrypted string
            return encryptedMessage;

        }

        /// <summary>
        /// Encode HTML for JSON
        /// </summary>
        /// <param name="text">Input text</param>
        /// <returns>Text ready for JSON</returns>
        public static string JsonHtml(string text)
        {

            // Break if no text
            if (text == null) 
                return string.Empty;

            // Escape backslashes, quotes, and 
            text = text.Replace("\\", "\\\\");
            text = text.Replace("\"", "\\\"");
            text = new Regex("\r|\n|\n\r", RegexOptions.IgnoreCase).Replace(text, "\\r");

            // DO IT!
            return text;

        }

        /// <summary>
        /// Generates a new GUID
        /// </summary>
        /// <returns></returns>
        public static string NewGuid
        {

            // DO IT!
            get
            {
                return Guid.NewGuid().ToString();
            }

        }

        /// <summary>
        /// Strip HTML tags
        /// </summary>
        /// <param name="text">Input text</param>
        /// <returns>Text with HTML tags removed</returns>
        public static string RemoveHtml(string text)
        {

            // DO IT!
            return Regex.Replace(text, @"<(.|\n)*?>", " ");

        }

        /// <summary>
        /// Strips non-alphanumeric characters from string
        /// </summary>
        /// <param name="text">Input text</param>
        /// <returns>Cleaned text</returns>
        public static string ToAlphaNumeric(string text)
        {

            // Remove non-alpha numeric characters
            return Regex.Replace(text, @"[^a-zA-Z0-9]", "");

        }

        /// <summary>
        /// Makes text XML-attribute friendly
        /// </summary>
        /// <param name="text">Input text</param>
        /// <returns>Cleaned text</returns>
        public static string ToAttribute(string text)
        {

            // Remove characters that might break XML attribute
            return Regex.Replace(text, @"[^a-zA-Z!#-%(-9 ]", "");

        }

        /// <summary>
        /// Convert string to title case
        /// </summary>
        /// <param name="title">The string to convert</param>
        /// <returns>Title case string</returns>
        public static string ToTitleCase(string title)
        {

            // Split title to words
            string[] words = title.Split(" ".ToCharArray());

            // Clear input string to return it
            title = string.Empty;
            foreach (string word in words)
            {

                // Capitalize first letter
                if (word.Length > 0) title += word.Substring(0, 1).ToUpper();
                if (word.Length > 1) title += word.Substring(1, word.Length - 1) + " ";

            }

            // Return formatted title
            return title;

        }

        /// <summary>
        /// Regular expression to validate e-mail address
        /// </summary>
        public static Regex ValidEmail = new Regex(@"^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$", RegexOptions.IgnoreCase);

        /// <summary>
        /// Build regular expression pattern to validate file types
        /// </summary>
        /// <param name="type">Type from FilePatternType enumeration</param>
        /// <returns>Regex to validate file types</returns>
        public static Regex ValidFile(FilePatternType type)
        {

            // Initialize output string
            string output = string.Empty;

            // Key of type
            switch (type)
            {

                case FilePatternType.ALL:

                    // Build build of all file types
                    output += "(" + string.Join(")|(", Settings.EXT_ATTACHMENT) + ")|";
                    output += "(" + string.Join(")|(", Settings.EXT_IMAGE) + ")|";
                    output += "(" + string.Join(")|(", Settings.EXT_MEDIA) + ")";

                    break;
                case FilePatternType.ATTACHMENT:

                    // Build list of attachment types
                    output += "(" + string.Join(")|(", Settings.EXT_ATTACHMENT) + ")";

                    break;
                case FilePatternType.IMAGE:

                    // Build list of image types
                    output += "(" + string.Join(")|(", Settings.EXT_IMAGE) + ")";

                    break;
                case FilePatternType.MEDIA:

                    // Build list of embeddable media file types
                    output += "(" + string.Join(")|(", Settings.EXT_MEDIA) + ")";

                    break;

            }

            // Return regex
            return new Regex(@"^.+\.(" + output + ")$", RegexOptions.IgnoreCase);

        }

        /// <summary>
        /// Regular expression to validate GUID
        /// </summary>
        public static Regex ValidGuid = new Regex(@"^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$", RegexOptions.IgnoreCase);

        /// <summary>
        /// Regular expression to validate Vimeo URL
        /// </summary>
        public static Regex ValidVimeo = new Regex(@"vimeo\.com/(?:.*#|.*/videos/)?([0-9]+)", RegexOptions.IgnoreCase);

        /// <summary>
        /// Regular expression to validate YouTube URL
        /// </summary>
        public static Regex ValidYouTube = new Regex(@"youtu(?:\.be|be\.com)/(?:.*v(?:/|=)|(?:.*/)?)([a-zA-Z0-9-_]+)", RegexOptions.IgnoreCase);

    }

}
